// MFCTemplateView.cpp : implementation of the CMFCTemplateView class
//

#include "stdafx.h"
#include "MFCTemplate.h"

#include "MFCTemplateDoc.h"
#include "MFCTemplateView.h"

#include "GL.h" 
#include "glut.h"
#include "GLU.h"
#include <math.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

GLfloat angle;
GLfloat angle1;
#define DEG2RAD (3.14159f/180.0f)
#define PI 3.1415926535898

const float CMFCTemplateView::m_tetra_vertices[][3] = {
	{0.0, 0.0, 1.0},
	{0.0, 0.942809, -0.33333},
	{-0.816497, -0.471405, -0.33333},
	{0.816497, -0.471405, -0.33333}
};

// CMFCTemplateView

IMPLEMENT_DYNCREATE(CMFCTemplateView, CView)

BEGIN_MESSAGE_MAP(CMFCTemplateView, CView)
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
	ON_WM_CREATE()
	ON_WM_PAINT()
	ON_WM_SIZE()
	ON_WM_DESTROY()
	ON_WM_TIMER()
END_MESSAGE_MAP()

// CMFCTemplateView construction/destruction

CMFCTemplateView::CMFCTemplateView()
{
	// TODO: add construction code here

}

CMFCTemplateView::~CMFCTemplateView()
{
}

BOOL CMFCTemplateView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CView::PreCreateWindow(cs);
}

// CMFCTemplateView drawing

void CMFCTemplateView::OnDraw(CDC* /*pDC*/)
{
	CMFCTemplateDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: add draw code for native data here
}


// CMFCTemplateView printing

BOOL CMFCTemplateView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CMFCTemplateView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CMFCTemplateView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}


// CMFCTemplateView diagnostics

#ifdef _DEBUG
void CMFCTemplateView::AssertValid() const
{
	CView::AssertValid();
}

void CMFCTemplateView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CMFCTemplateDoc* CMFCTemplateView::GetDocument() const // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMFCTemplateDoc)));
	return (CMFCTemplateDoc*)m_pDocument;
}
#endif //_DEBUG


// CMFCTemplateView message handlers
void CMFCTemplateView::SetupOpenGL(void)
{
	//Declare Pixel Format
	static PIXELFORMATDESCRIPTOR pfd =
	{
		sizeof(PIXELFORMATDESCRIPTOR),
		1,
		PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
		PFD_TYPE_RGBA,
		32, // bit depth
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		16, // z-buffer depth
		0, 0, 0, 0, 0, 0, 0,
	};

	// Get device context only once.
	HDC hdc = GetDC()->m_hDC;
	
	// Set Pixel format.
	int nPixelFormat = ChoosePixelFormat(hdc, &pfd);
	SetPixelFormat(hdc, nPixelFormat, &pfd);

	// Create the OpenGL Rendering Context.
	m_hRC = wglCreateContext(hdc);
	wglMakeCurrent(hdc, m_hRC);
}
int CMFCTemplateView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;

	// TODO:  Add your specialized creation code here
	//Setup Opengl
	// bai 5
	SetupOpenGL();
	//Create Timer
	SetTimer(1, 100, NULL);
	//bai 6
    InitOpenGL();

	return 0;
}


void CMFCTemplateView::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: Add your message handler code here and/or call default

	CView::OnTimer(nIDEvent);
	
	//RePaint the window
	angle	+= 10;
	if(angle > 360) angle = angle - 360.0f;
	
	InvalidateRect(NULL, false);
}


void CMFCTemplateView::OnPaint()
{
	CPaintDC dc(this); // device context for painting
	// TODO: Add your message handler code here
	// Do not call CView::OnPaint() for painting messages
	
	//bai 1
	/*glClear(GL_COLOR_BUFFER_BIT); 
	//glColor3f(1.0f, 0.0f, 0.0f);
	glBegin(GL_POINTS);        
	GLint circle_points = 36;
	for( int i=0; i<circle_points; i++ ) {
		angle = i * (2.0*PI/circle_points);
		float X = cos(angle)*0.5; //radius==0.5
		float Y = sin(angle)*0.5;
		glVertex2f( X, Y );
	}
	glEnd();
	glFlush();
	*/

	// bai 2
	/*	glClear(GL_COLOR_BUFFER_BIT); 
	//glColor3f(1.0f, 0.0f, 0.0f);
	glBegin(GL_LINE_LOOP);        
	GLint circle_points = 36;
	for( int i=0; i<circle_points; i++ ) {
		angle = i * (2.0*PI/circle_points);
		float X = cos(angle)*0.5; //radius==0.5
		float Y = sin(angle)*0.5;
		glVertex2f( X, Y );
	}
	glEnd();
	glFlush(); 
   */

	// bai 3
	/*
		glClear(GL_COLOR_BUFFER_BIT); 
	//glColor3f(1.0f, 0.0f, 0.0f);
	glBegin(GL_LINES);
	GLint circle_points = 36;
	for( int i=0; i<circle_points; i++ ) {
		glVertex2d(0,0);
		angle = i * (2.0*PI/circle_points);
		float X = cos(angle)*0.5; //radius==0.5
		float Y = sin(angle)*0.5;
		glVertex2f( X, Y );
	}
	glEnd();
	glBegin(GL_LINE_LOOP);
	for( int i=0; i<circle_points; i++ ) {
		angle = i * (2.0*PI/circle_points);
		float X = cos(angle)*0.5; //radius==0.5
		float Y = sin(angle)*0.5;
		glVertex2f( X, Y );
	}
	glEnd();
	glFlush(); 
	*/

	//bai 4
	/*    glClear(GL_COLOR_BUFFER_BIT); 
	//glColor3f(1.0f, 0.0f, 0.0f);
	glBegin(GL_TRIANGLES);
		GLint circle_points = 36;
		angle1 = (2.0*PI/circle_points);
		
		glVertex2d (0,0);
		glVertex2d(cos(0*angle1+angle)*0.5, sin(0*angle1+angle)*0.5);        
		glVertex2d(cos(angle1+angle)*0.5, sin(angle1+angle)*0.5);
		glVertex2d (0,0);
		glVertex2d(cos(12*angle1+angle)*0.5, sin(12*angle1+angle)*0.5);
		glVertex2d(cos(13*angle1+angle)*0.5, sin(13*angle1+angle)*0.5);
		glVertex2d (0,0);
		glVertex2d(cos(24*angle1+angle)*0.5, sin(24*angle1+angle)*0.5);
		glVertex2d(cos(25*angle1+angle)*0.5, sin(25*angle1+angle)*0.5);
	glEnd();
	glFlush();

	SwapBuffers(dc.m_ps.hdc);
	*/
	DrawMovingTetrahydron();
}



void CMFCTemplateView::OnSize(UINT nType, int cx, int cy)
{
	CView::OnSize(nType, cx, cy);

	// TODO: Add your message handler code here

	//Setting up viewport
	CRect rect;
	GetClientRect(rect);
	int size = min(rect.Width(), rect.Height());
	glViewport(0, 0, size, size);
}



void CMFCTemplateView::OnDestroy()
{
	CView::OnDestroy();

	RemoveOpenGL();
}


void CMFCTemplateView::RemoveOpenGL(void)
{
	//Delete Rendering Context
	if(wglGetCurrentContext() != NULL)
		wglMakeCurrent(NULL,NULL);

	if(m_hRC != NULL)
	{
		wglDeleteContext(m_hRC);
		m_hRC = NULL;
	}
}




void CMFCTemplateView::DrawPolygon(void)
{
	glClear(GL_COLOR_BUFFER_BIT); 
	glColor3f(1.0f, 0.0f, 0.0f);

	glBegin(GL_POLYGON);        
		glVertex2f(-0.5f,	-0.5f);        
		glVertex2f(-0.5,	0.5f);        
		glVertex2f(0.5,		0.5f);        
		glVertex2f(0.5,		-0.5f);   
	glEnd();
	glFlush();
}


void CMFCTemplateView::DrawMovingPolygon(void)
{
	glClear(GL_COLOR_BUFFER_BIT); 
	glColor3f(1.0f, 0.0f, 0.0f);

	GLfloat cx, cy;
	cx = 0.5*cos(DEG2RAD*m_angle); cy = 0.5*sin(DEG2RAD*m_angle);

	glBegin(GL_POLYGON);        
		glVertex2f(cx - 0.5, cy - 0.5);        
		glVertex2f(cx - 0.5, cy + 0.5);        
		glVertex2f(cx + 0.5, cy + 0.5);        
		glVertex2f(cx + 0.5, cy - 0.5);    
	glEnd();
	glFlush();	
}


void CMFCTemplateView::DrawTetrahydron(void)
{
	//setup viewwer - camera parameter: 
	//i.e., location (eye), 
	//direction (from eye to the reference point), and orientation (up vector)
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(
		0.0,	//eyeX
		0.0,	//eyeY
		4.5,	//eyeZ
		0.0,	//reference point X
		0.0,	//reference point Y
		0.0,	//reference point Z
		0.0,	//up vector X
		1.0,	//up vector Y
		0.0		//up vector Z
		);
	
	//clear frame buffer
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
	
	//the order of the vertices in triangle is important!
	glBegin(GL_TRIANGLES);  
		//Face 1: defined by vertices: 0, 2, 1; colored: red
		glColor3f(1.0f, 0.0f, 0.0f);
		glVertex3fv(m_tetra_vertices[0]);
		glVertex3fv(m_tetra_vertices[2]);
		glVertex3fv(m_tetra_vertices[1]);

		//Face 2: defined by vertices: 0, 1, 3; colored: green
		glColor3f(0.0f, 1.0f, 0.0f);
		glVertex3fv(m_tetra_vertices[0]);
		glVertex3fv(m_tetra_vertices[1]);
		glVertex3fv(m_tetra_vertices[3]);

		//Face 3: defined by vertices: 0, 3, 2; colored: blue
		glColor3f(0.0f, 0.0f, 1.0f);
		glVertex3fv(m_tetra_vertices[0]);
		glVertex3fv(m_tetra_vertices[3]);
		glVertex3fv(m_tetra_vertices[2]);

		//Face 4: defined by vertices: 3, 1, 2; colored: black
		glColor3f(0.0f, 0.0f, 0.0f);
		glVertex3fv(m_tetra_vertices[3]);
		glVertex3fv(m_tetra_vertices[1]);
		glVertex3fv(m_tetra_vertices[2]);

	glEnd();
	glFlush();
}
void CMFCTemplateView::DrawMovingTetrahydron(void)
{
	//setup viewwer - camera parameter: 
	//i.e., location (eye), 
	//direction (from eye to the reference point), and orientation (up vector)
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(
		2.0f*cos(DEG2RAD*m_angle),	//eyeX
		2.0f*sin(DEG2RAD*m_angle),	//eyeY
		3.5f,	//eyeZ
		0.0,	//reference point X
		0.0,	//reference point Y
		0.0,	//reference point Z
		0.0,	//up vector X
		1.0,	//up vector Y
		0.0		//up vector Z
		);
	
	//clear frame buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
	
	//the order of the vertices in triangle is important!
	glBegin(GL_TRIANGLES);  
		//Face 1: defined by vertices: 0, 2, 1; colored: red
		glColor3f(1.0f, 0.0f, 0.0f);
		glVertex3fv(m_tetra_vertices[0]);
		glVertex3fv(m_tetra_vertices[2]);
		glVertex3fv(m_tetra_vertices[1]);

		//Face 2: defined by vertices: 0, 1, 3; colored: green
		glColor3f(0.0f, 1.0f, 0.0f);
		glVertex3fv(m_tetra_vertices[0]);
		glVertex3fv(m_tetra_vertices[1]);
		glVertex3fv(m_tetra_vertices[3]);

		//Face 3: defined by vertices: 0, 3, 2; colored: blue
		glColor3f(0.0f, 0.0f, 1.0f);
		glVertex3fv(m_tetra_vertices[0]);
		glVertex3fv(m_tetra_vertices[3]);
		glVertex3fv(m_tetra_vertices[2]);

		//Face 4: defined by vertices: 3, 1, 2; colored: black
		glColor3f(0.0f, 0.0f, 0.0f);
		glVertex3fv(m_tetra_vertices[3]);
		glVertex3fv(m_tetra_vertices[1]);
		glVertex3fv(m_tetra_vertices[2]);

	glEnd();
	glFlush();	
}

void CMFCTemplateView::InitOpenGL(void)
{
	//setup projection type
	//glFrustrum: define viewing volume
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glFrustum(
				-1.0,	//left
				1.0,	//right
				-1.0,	//bottom
				1.0,	//top
				2.0,	//near
				10.0	//far
				);
	//Default MatrixMode is MODELVIEW 
	glMatrixMode(GL_MODELVIEW);

	//setup background color, or clear color
	glClearColor(0.1f, 0.7f, 0.7f, 1.0f);

	//setup foreground color
	glColor3f(0.1f, 0.0f, 0.0f);

	//Enable using depth info to remove hidden surface
	glEnable(GL_DEPTH_TEST);
}